<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>数组的解构赋值</title>
</head>
<body>
    <script>
        /* ES6 允许按照一定模式，从数组和对象中提取值，对变量进行赋值，这被称为解构 */
        // 标准：
        let [a, b, c] = [1, 2, 3]

        // 以下为一些例子及显示
        let [foo, [[bar], baz]] = [1, [[2], 3]];
        foo // 1
        bar // 2
        baz // 3

        let [ , , third] = ["foo", "bar", "baz"];
        third // "baz"

        let [x, , y] = [1, 2, 3];
        x // 1
        y // 3

        let [head, ...tail] = [1, 2, 3, 4];
        head // 1
        tail // [2, 3, 4]

        let [x, y, ...z] = ['a'];
        x // "a"
        y // undefined
        z // []

        // 如果解构不成功，变量的值就为 undefined
        let [fooo] = [] // fooo => undefined
        let [barr, fooo] = [1] // barr => 1; fooo => undefined

        // 不完全解构，就是等号左边的模式 只匹配一部分等号右边的数组
        let [u, i, p] = [1, 2] // u => 1; i => 2
        let [q, [w, e], r] = [1, [2], 3] // q => 1; w => 2; r => 3

        // 等号右边的不是数组(形如[1, 3, 4])的话，报错
        // 报错
        let [foo] = 1;
        let [foo] = false;
        let [foo] = NaN;
        let [foo] = undefined;
        let [foo] = null;
        let [foo] = {};

        // 对于Set结构，也可以用数据解构赋值
        let [x, y, z] = new Set(['a', 'b', 'c']);
        x // "a"
        
        /* 只要某种数据结构具有 Iterator【遍历器】 接口，都可以采用数组形式的解构赋值。*/

        /* Iterator【遍历器】
            为各种数据结构提供统一的访问机制，任何数据结构只要部署了它，就可以遍历
        */

        /* 数组 和 类数组对象
            数组：var arr = [1, 2, 3] // arr[0]=>1; arr[1]=>2; arr[2]=>3; arr.length=>3
            类数组对象：var arr2 = {0: 1, 1: 2, 2: 3, length: 3} // // arr2[0]=>1; arr2[1]=>2; arr2[2]=>3; arr2.length=>3
            两个都可以遍历(就是能用for)
        */

        /* 关于解构赋值允许指定默认值的问题 */
        let [foo = true] = []; // true
        let [x, y = 'b'] = ['a']; // x='a', y='b'
        let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
        // 注意一点：在ES6中，使用的 === 严格相等运算符
        // 只有当一个数组成员【严格等于】undefined，默认值才会生效。

        let [x = 1] = [undefined]; // 1
        let [x = 1] = [null]; // null
        // null === undefined --> false; null == undefined --> true 注意是严格相等符

        /* 默认值是个表达式的话，该表达式不会立即求值，只有在用到的时候才会求值【惰性求值】 */
        function fn1(){
            console.log('aaa')
        }
        let [x = fn()] = [1]
        /* 默认值可以引用解构赋值的其他变量，但该变量必须已经声明 */
        let [x = 1, y = x] = [];     // x=1; y=1
        let [x = 1, y = x] = [2];    // x=2; y=2
        let [x = 1, y = x] = [1, 2]; // x=1; y=2
        let [x = y, y = 1] = [];     // ReferenceError: y is not defined
    </script>
</body>
</html>